package draftMate;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import draftMate.player.Position;

import draftMate.player.Hitter;
import draftMate.player.Pitcher;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;

public class DraftMate {
	final public static int NUMBATS = 325; // subject to change
	final public static int NUMARMS = 225;
        final public static int DEFAULT_NUM_TEAMS = 10;
        	
	private ArrayList<Hitter> hitterPool;
	private ArrayList<Pitcher> pitcherPool;
	private ArrayList<Team> teams;
        
        public DraftMate() {
            hitterPool = new ArrayList<>(NUMBATS);
            pitcherPool = new ArrayList<>(NUMARMS);
            teams = new ArrayList<>(DEFAULT_NUM_TEAMS);
        }
	
	/**
	 * loads pitchers contained in filename into pitcher pool
         * if pitchers are already loaded they are overwritten
	 * @param filename name of .csv file containing FANS pitcher projections
	 */
	public void importPitchers(String filename) {
		String name;
		double wins, ER, walks, hits, ip, k, saves;
		File f = null;
		BufferedReader br = null;
		String line = null;
		StringTokenizer st = null;
		
		try {
			f = new File(filename);
			br = new BufferedReader(new FileReader(f));
			br.readLine(); // gets rid of first line
			
			while((line = br.readLine()) != null ) {
				st = new StringTokenizer(line, ",\"");
				name = st.nextToken().toLowerCase();
				wins = Double.parseDouble(st.nextToken());
				
				for (int j = 0; j < 4; j++) {
					st.nextToken(); // skips L, ERA, GS, G
				}
				
				saves = Double.parseDouble(st.nextToken());
				ip = Double.parseDouble(st.nextToken());
				hits = Double.parseDouble(st.nextToken());
				ER = Double.parseDouble(st.nextToken());
				
				st.nextToken(); // skip HR
				
				k = Double.parseDouble(st.nextToken());
				walks = Double.parseDouble(st.nextToken());
				
				Pitcher toAdd = new Pitcher(name, wins, ER, walks, hits, ip, k, saves);
				pitcherPool.add(toAdd);
                                
			}
		} catch (IOException e) {
			System.err.println("An error occured while importing pitchers from " +
								filename);
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				System.err.println("Problem closing file input stream.");
			}
		}
        }
	
	/**
	 * loads hitters contained in file into the hitter pool
         * .csv files should be grouped by position
	 * @param filename name of .csv file containing FANS projections
         * @param pos position of hitters in csv 
	 */
	public void importHitters(String filename, String pos) {
		String name;
                Double ab, hits, hr, runs, rbi, steals;
		
		File f = null;
		BufferedReader br = null;
		String line = null;
		StringTokenizer st = null;
		
		try {
			f = new File(filename);
                        if(f.canRead()) System.out.println("fuck you");
			br = new BufferedReader(new FileReader(f));
			br.readLine(); // gets rid of first line
			
			while((line = br.readLine()) != null ) {
				st = new StringTokenizer(line, ",\"");
				name = st.nextToken().toLowerCase();
				
				st.nextToken(); // skips games
				
				ab = Double.parseDouble(st.nextToken());
				hits = Double.parseDouble(st.nextToken());
				
				for (int j = 0; j < 2; j++) {
					st.nextToken(); // skips 2B, 3B
				}
				
				hr = Double.parseDouble(st.nextToken());
				runs = Double.parseDouble(st.nextToken());
				rbi = Double.parseDouble(st.nextToken());
				
				for (int j = 0; j < 3; j++) {
					st.nextToken(); // skip walks, Ks, HBP
				}
				
				steals = Double.parseDouble(st.nextToken());
                                
                                // if a hitter is listed in > 1 position file, we need to modify his pos
                                // rather than creating a seperate object for each position he plays
                                // findhitter returns null if a player with all the same fields does not
                                // yet exist in the hitter pool. If the player is already in the pool, we need
                                // to simply add a "/<pos>" to his position to indicate the added eligibility
                                Hitter h = findHitter(name, ab, hits, hr, runs, rbi, steals);
                                if (h == null) {
                                    Hitter toAdd = new Hitter(name, ab, hits, hr, runs, rbi, steals, pos);    
                                    hitterPool.add(toAdd);
                                } else {
                                    h.setPos(h.getPos() + "/" + pos);
                                }   
                        }
		} catch (IOException e) {
			System.err.println("An error occured while importing pitchers from" +
								filename);
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				System.err.println("An error occured while closing the file stream");
			}
		}
        }
	
        /**
         * looks up the hitter by name and stats and returns the Hitter object
         * if no such hitter is already in the hitter pool, returns null
         * @param name
         * @return hitter object matching the parameter fields, null if no such
         * hitter exists
         */
        Hitter findHitter(String name, double ab, double hits, double hr, double runs,
                double rbi, double steals) {
            for (Hitter h : hitterPool) {
                if (h.getName().equals(name) && h.getAb() == ab && h.getHits() == hits
                        && h.getHr() == hr && h.getRuns() == runs && h.getRbi() == rbi
                        && h.getSteals() == steals) {
                    return h;
                }
            } return null;
        }
        
        /**
         * takes a hitter out of the hitter pool and into a team
         * @param playerIndex index of hitter in hitter
         * @param teamIndex index of team in teams
         */
        public void draftHitter(int hitterIndex, int teamIndex) {
            teams.get(teamIndex).addHitter(hitterPool.remove(hitterIndex));
        }
        
        public void draftPitcher(int pitcherIndex, int teamIndex) {
            teams.get(teamIndex).addPitcher(pitcherPool.remove(pitcherIndex));
        }
        
        public void undraftHitter(int hitterIndex, int teamIndex) {
            hitterPool.add(teams.get(teamIndex).removeHitter(hitterIndex));
        }
        
        public void undraftPitcher(int pitcherIndex, int teamIndex) {
            pitcherPool.add(teams.get(teamIndex).removePitcher(pitcherIndex));
        }
        
	/**
         * add a new team to the draft
         * @param teamName 
         */
	public void addTeam(String teamName) {
            teams.add(new Team(teamName));
	}
	
        /**
         * 
         * @return number of Hitters in pool
         */
        public int numHitters() {
            return hitterPool.size();
        }

        /**
         * 
         * @return number of Pitchers in pool
         */
        public int numPitchers() {
            return pitcherPool.size();
        }
        
        /**
         * 
         * @return number of teams in draft
         */
        public int numTeams() {
            return teams.size();
        }
        
        public Team getTeam(int index) {
            return teams.get(index);
        }
        
        /**
         * 
         * @param name name of team
         * @return true if team name is already in use, false otherwise
         */
        public boolean teamExists(String name) {
            for (Team t : teams) {
                if (t.getName().equals(name)) {
                    return true;
                }
            } return false;
        }
        
        public Object getTeamStat(int row, int col) {
            return teams.get(row).getValAt(col);
        }
        
        public Object getHitterStat(int row, int col) {
            return hitterPool.get(row).getValAt(col);
        }
        
        public Object getPitcherStat(int row, int col) {
            return pitcherPool.get(row).getValAt(col);
        }
	/**
	 * 
	 * @param team team to get projections for
	 * @return a string containing team's projections, given the
	 * current roster
	 */
	public String getProjections(Team team) {
		return ("Wins\tKs\tERA\tWHIP\tSaves\tRuns\tRBIs\tHRs\tSteals\tAvg\n" +
				team.getpWins() + "\t" + team.getpK() + "\t" + team.getpERA() +
				"\t" + team.getpWHIP() + "\t" + team.getpSaves() + "\t" +
				team.getpRuns() + "\t" + team.getpRBI() + "\t" + team.getpHR() +
				"\t" + team.getpSteals() + "\t" + team.getpAB());
	}
        
        /**
         * saves the draft to disk
         * @param file file to save draft to.  If file exists, overwrite.
         */
        public void saveDraft(File file) throws FileNotFoundException, UnsupportedEncodingException {
            FileWriter writer = null;
            
            try {
                writer = new FileWriter(file);
                
                // first write all hitters in hitter pool on seperate line
                writer.write(Integer.toString(hitterPool.size()) + "\n");
                for (Hitter h : hitterPool) {
                    writer.write(h.toString() + "\n");
                }
                
                // then write all pitchers in pitcher pool on seperate line
                writer.write(Integer.toString(pitcherPool.size()) + "\n");
                for (Pitcher p : pitcherPool) {
                    writer.write(p.toString() + "\n");
                }
                
                //  then for each team, write the team name on its own line
                // followed by all hitters on seperate lines
                // followed by all pitchers on seperate lines
                writer.write(Integer.toString(teams.size()) + "\n");
                for (Team t : teams) {
                    writer.write(t.getName() + "\n" +
                            Integer.toString(t.getNumHitters()) + "\n");
                    
                    for (int i = 0; i < t.getNumHitters(); i++) {
                        writer.write(t.getHitter(i).toString() + "\n");
                    }
                    
                    writer.write(Integer.toString(t.getNumPitchers()) + "\n");
                    for (int i = 0; i < t.getNumPitchers(); i++) {
                        writer.write(t.getPitcher(i).toString() + "\n");
                    }
                   
                    writer.flush();
                }            
            } catch (IOException x) {
                x.printStackTrace();
            } finally {
                try {
                    writer.close();
                } catch (IOException ex) {
                    Logger.getLogger(DraftMate.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        
        public void openDraft(File file) {
            
            FileReader fr = null;
            BufferedReader br = null;
            StringTokenizer st = null;
            String line, name, teamName;
            char pos;
            double ab, h, r, rbi, hr, sb, w, k, sv, er, bb, ip;
            int numHitters, numPitchers, numTeams = 0;
            Hitter toAddH = null;
            Pitcher toAddP = null;
            Team toAddT = null;
            
            try {
                fr = new FileReader(file);
                br = new BufferedReader(fr);
                
                // first get number of hitters in pool
                numHitters = Integer.parseInt(br.readLine());
                
                // then load each hitter into the hitter pool
                for (int i = 0; i < numHitters; i++) {
                    hitterPool.add(getHitterFromFile(br));
                }
                
                // then get number of pitchers in pool
                numPitchers = Integer.parseInt(br.readLine());
                
                // load each pitcher into pitcher pool
                for (int i = 0; i < numPitchers; i++) {
                    pitcherPool.add(getPitcherFromFile(br));
                } 
                
                // now get the number of teams
                numTeams = Integer.parseInt(br.readLine());
                
                for (int i = 0; i < numTeams; i++) {
                    teamName = br.readLine();
                    teams.add(new Team(teamName)); // add() adds to back
                    
                    // now get num hitters on team
                    numHitters = Integer.parseInt(br.readLine());
                    
                    // create all hitters on team and put them on team
                    for (int j = 0; j < numHitters; j++) {
                        teams.get(i).addHitter(getHitterFromFile(br));
                    }
                    
                    // get num pitchers on team
                    numPitchers = Integer.parseInt(br.readLine());

                    // create all pitchers on team and put them on team
                    for (int j = 0; j < numPitchers; j++) {
                        teams.get(i).addPitcher(getPitcherFromFile(br));
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        
        private Hitter getHitterFromFile(BufferedReader br) {
            Double r, rbi, hr, sb, ab, h;
            String line, name, pos;
            StringTokenizer st = null;
            Hitter toAddH = null;
            
            try {
                line = br.readLine();
                st = new StringTokenizer(line, ",");
                name = st.nextToken();
                r = Double.parseDouble(st.nextToken());
                rbi = Double.parseDouble(st.nextToken());
                hr = Double.parseDouble(st.nextToken());
                sb = Double.parseDouble(st.nextToken());
                pos = st.nextToken();
                ab = Double.parseDouble(st.nextToken());
                h = Double.parseDouble(st.nextToken());
                
                
                return new Hitter(name, ab, h, hr, r, rbi, sb, pos);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }

        private Pitcher getPitcherFromFile(BufferedReader br) {
            String line, name;
            double w, k, sv, er, bb, h, ip;
            StringTokenizer st = null;
            
            try {
                line = br.readLine();
                st = new StringTokenizer(line, ",");
                name = st.nextToken();
                w = Double.parseDouble(st.nextToken());
                k = Double.parseDouble(st.nextToken());
                sv = Double.parseDouble(st.nextToken());
                er = Double.parseDouble(st.nextToken());
                bb = Double.parseDouble(st.nextToken());
                h = Double.parseDouble(st.nextToken());
                ip = Double.parseDouble(st.nextToken());
                
                return new Pitcher(name, w, er, bb, h, ip, k, sv);
            }
            catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
        
        public void clearData() {
            hitterPool.clear();
            pitcherPool.clear();
            teams.clear();
        }
}
